<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据库ER图生成工具</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f0f2f5;
            color: #333;
        }
        .container {
            max-width: 1400px;
            margin: 0 auto;
            background-color: white;
            padding: 25px;
            border-radius: 8px;
            box-shadow: 0 2px 15px rgba(0,0,0,0.08);
        }
        h1 {
            color: #2c3e50;
            margin-bottom: 25px;
            font-size: 28px;
            font-weight: 600;
        }
        .form-group {
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            color: #495057;
        }
        input, select {
            width: 100%;
            padding: 10px;
            box-sizing: border-box;
            border: 1px solid #ced4da;
            border-radius: 4px;
            font-size: 14px;
            transition: border-color 0.3s;
        }
        input:focus, select:focus {
            outline: none;
            border-color: #007bff;
            box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
        }
        button {
            background-color: #007bff;
            color: white;
            border: none;
            padding: 12px 20px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: background-color 0.3s;
        }
        button:hover {
            background-color: #0056b3;
        }
        .table-node {
            border: 2px solid #dee2e6;
            border-radius: 8px;
            background-color: white;
            box-shadow: 0 2px 8px rgba(0,0,0,0.05);
            transition: all 0.3s ease;
        }
        .table-node:hover {
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
            border-color: #007bff;
        }
        .table-header {
            background-color: #007bff;
            color: white;
            padding: 12px;
            border-top-left-radius: 6px;
            border-top-right-radius: 6px;
            font-weight: 500;
        }
        .table-body {
            padding: 10px;
        }
        .table-name {
            font-weight: 600;
            text-align: center;
            margin: 0;
            font-size: 14px;
        }
        .table-column {
            font-size: 13px;
            padding: 4px 8px;
            display: flex;
            align-items: center;
            border-bottom: 1px solid #f0f0f0;
        }
        .table-column:last-child {
            border-bottom: none;
        }
        .column-name {
            flex: 1;
            font-weight: 500;
        }
        .column-type {
            color: #6c757d;
            font-size: 12px;
            margin-left: 8px;
        }
        .primary-key {
            color: #dc3545;
            font-weight: 600;
        }
        .foreign-key {
            color: #17a2b8;
            position: relative;
        }
        .relationship-line {
            stroke: #495057;
            stroke-width: 1.5;
            fill: none;
            marker-end: url(#arrowhead);
            stroke-dasharray: 2;
        }
        .relationship-group {
            pointer-events: none;
        }
        .relationship-label {
            font-size: 12px;
            fill: #007bff;
            font-weight: 500;
        }
        /* 确保关系标签显示在最上层 */
        .relationship-group text {
            font-weight: bold;
            font-size: 16px;
            text-shadow: 2px 2px 4px rgba(255,255,255,0.8), -2px -2px 4px rgba(255,255,255,0.8), 2px -2px 4px rgba(255,255,255,0.8), -2px 2px 4px rgba(255,255,255,0.8);
        }
        .relationship-group rect {
            stroke-width: 2px;
            stroke: #333;
        }
        .table-text {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        .error {
            color: #dc3545;
            margin-top: 15px;
            padding: 12px;
            background-color: #f8d7da;
            border-radius: 4px;
            border-left: 4px solid #dc3545;
        }
        .success {
            color: #28a745;
            margin-top: 15px;
            padding: 12px;
            background-color: #d4edda;
            border-radius: 4px;
            border-left: 4px solid #28a745;
        }
        #er-diagram {
            margin-top: 25px;
            border: 1px solid #dee2e6;
            border-radius: 8px;
            background-color: #f8f9fa;
            overflow: auto;
            min-height: 700px;
            padding: 20px;
        }
        .table-info {
            margin-top: 20px;
            padding: 15px;
            background-color: #f8f9fa;
            border-radius: 6px;
            border: 1px solid #dee2e6;
        }
        .column-info {
            margin-left: 25px;
            margin-top: 8px;
        }
        .info-label {
            font-weight: 500;
            color: #495057;
        }
        .info-value {
            margin-left: 8px;
            color: #6c757d;
        }
        .badge {
            display: inline-block;
            padding: 2px 8px;
            font-size: 11px;
            font-weight: 500;
            line-height: 1;
            color: white;
            background-color: #6c757d;
            border-radius: 12px;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            margin-left: 6px;
        }
        .badge-primary {
            background-color: #007bff;
        }
        .badge-success {
            background-color: #28a745;
        }
        .badge-danger {
            background-color: #dc3545;
        }
        .table-checkbox {
            cursor: pointer;
        }
        
        .table-checkbox:checked + label {
            color: #007bff;
            font-weight: 500;
        }
        
        .form-check-label {
            cursor: pointer;
            user-select: none;
        }
        
        .form-check-label:hover {
            color: #0056b3;
        }
        
        .table-item {
            padding: 8px 12px;
            border-radius: 4px;
            transition: background-color 0.2s;
        }
        
        .table-item:hover {
            background-color: #f8f9fa;
        }
        
        .table-search {
            border-radius: 20px;
            border: 1px solid #ced4da;
            padding: 6px 12px;
            font-size: 0.875rem;
        }
        
        .table-search:focus {
            border-color: #007bff;
            box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
        }
        
        .table-item.hidden {
            display: none !important;
        }
        
        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }
        .fade-in {
            animation: fadeIn 0.5s ease-in-out;
        }
    </style>
</head>
<body>
    <div class="container-fluid">
        <div class="row">
            <div class="col-12">
                <h1 class="text-center mt-4 mb-4">
                    <i class="fas fa-database"></i> 数据库ER图生成工具
                </h1>
            </div>
        </div>
        
        <div class="row">
            <div class="col-md-3">
                <div class="connection-form">
                    <h5><i class="fas fa-cog"></i> 数据库连接设置</h5>
                    <form id="connectionForm">
                        <div class="mb-3">
                            <label for="dbType" class="form-label">数据库类型</label>
                            <select class="form-select" id="dbType" required>
                                <option value="mysql">MySQL</option>
                                <option value="postgresql">PostgreSQL</option>
                                <option value="sqlserver">SQL Server</option>
                                <option value="sqlite" selected>SQLite</option>
                            </select>
                        </div>
                        
                        <div class="mb-3" id="hostGroup">
                            <label for="host" class="form-label">主机地址</label>
                            <input type="text" class="form-control" id="host" value="localhost">
                        </div>
                        
                        <div class="mb-3" id="portGroup">
                            <label for="port" class="form-label">端口</label>
                            <input type="number" class="form-control" id="port" value="3306">
                        </div>
                        
                        <div class="mb-3">
                            <label for="database" class="form-label">数据库名称</label>
                            <input type="text" class="form-control" id="database" required>
                        </div>
                        
                        <div class="mb-3" id="usernameGroup">
                            <label for="username" class="form-label">用户名</label>
                            <input type="text" class="form-control" id="username">
                        </div>
                        
                        <div class="mb-3" id="passwordGroup">
                            <label for="password" class="form-label">密码</label>
                            <input type="password" class="form-control" id="password">
                        </div>
                         
                        <div class="mb-3">
                            <label for="relationshipStyle" class="form-label">关系线样式</label>
                            <select class="form-select" id="relationshipStyle">
                                <option value="straight">直线</option>
                                <option value="curve">曲线</option>
                            </select>
                        </div>
                        
                        <button type="submit" class="btn btn-primary w-100">
                            <i class="fas fa-search"></i> 分析数据库
                        </button>
                    </form>
                </div>
                
                <div id="tableInfo" class="table-info" style="display: none;">
                    <div class="d-flex justify-content-between align-items-center mb-3">
                        <h6 class="mb-0"><i class="fas fa-info-circle"></i> 表信息</h6>
                        <div class="btn-group btn-group-sm">
                            <button type="button" class="btn btn-outline-primary" id="selectAllBtn">全选</button>
                            <button type="button" class="btn btn-outline-secondary" id="deselectAllBtn">全不选</button>
                        </div>
                    </div>
                    <div class="mb-3">
                        <input type="text" class="form-control form-control-sm" id="tableSearch" placeholder="搜索表名...">
                    </div>
                    <div id="tableList"></div>
                    <div class="mt-3">
                        <button type="button" class="btn btn-success btn-sm w-100" id="refreshDiagramBtn">
                            <i class="fas fa-sync-alt"></i> 刷新ER图
                        </button>
                    </div>
                </div>
            </div>
            
            <div class="col-md-9">
                <div class="er-diagram" id="erDiagram">
                    <div class="loading" id="loading">
                        <div class="spinner-border text-primary" role="status">
                            <span class="visually-hidden">加载中...</span>
                        </div>
                        <p class="mt-3">正在分析数据库结构...</p>
                    </div>
                    
                    <div class="text-center text-muted" id="placeholder" style="padding: 100px;">
                        <i class="fas fa-database fa-3x mb-3"></i>
                        <p>请设置数据库连接信息并点击"分析数据库"按钮</p>
                    </div>
                </div>
                
                <div class="alert alert-danger error-message" id="errorMessage"></div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 页面加载时初始化数据库连接表单
        document.addEventListener('DOMContentLoaded', function() {
            // 触发一次数据库类型切换事件，确保初始状态正确
            const dbTypeSelect = document.getElementById('dbType');
            const event = new Event('change');
            dbTypeSelect.dispatchEvent(event);
        });
        let currentData = null;
        
        // 判断关系类型的函数
        function getRelationshipType(relationship) {
            // 这里可以根据外键约束信息判断关系类型
            // 1:1 - 一对一关系
            // 1:N - 一对多关系  
            // N:M - 多对多关系
            
            // 简单的启发式规则：
            // 如果外键列有唯一约束，可能是1:1关系
            // 否则通常是1:N关系
            // 多对多关系通常通过中间表实现，这里显示为N:M
            
            if (relationship.is_unique) {
                return '1:1';
            } else if (relationship.is_many_to_many) {
                return 'N:M';
            } else {
                return '1:N';
            }
        }
        
        // 数据库类型切换
        document.getElementById('dbType').addEventListener('change', function() {
            const dbType = this.value;
            const hostGroup = document.getElementById('hostGroup');
            const portGroup = document.getElementById('portGroup');
            const usernameGroup = document.getElementById('usernameGroup');
            const passwordGroup = document.getElementById('passwordGroup');
            
            if (dbType === 'sqlite') {
                if (hostGroup) hostGroup.style.display = 'none';
            if (portGroup) portGroup.style.display = 'none';
            if (usernameGroup) usernameGroup.style.display = 'none';
            if (passwordGroup) passwordGroup.style.display = 'none';
            } else {
                if (hostGroup) hostGroup.style.display = 'block';
                if (portGroup) portGroup.style.display = 'block';
                if (usernameGroup) usernameGroup.style.display = 'block';
                if (passwordGroup) passwordGroup.style.display = 'block';
            }
            
            // 设置默认端口
            const ports = {
                'mysql': 3306,
                'postgresql': 5432,
                'sqlserver': 1433
            };
            if (ports[dbType]) {
                document.getElementById('port').value = ports[dbType];
            }
        });
        
        // 表单提交
        document.getElementById('connectionForm').addEventListener('submit', async function(e) {
            e.preventDefault();
            
            const loading = document.getElementById('loading');
            const placeholder = document.getElementById('placeholder');
            const errorMessage = document.getElementById('errorMessage');
            const tableInfo = document.getElementById('tableInfo');
            
            if (loading) loading.style.display = 'block';
            if (placeholder) placeholder.style.display = 'none';
            if (errorMessage) errorMessage.style.display = 'none';
            if (tableInfo) tableInfo.style.display = 'none';
            
            const formData = {
                db_type: document.getElementById('dbType').value,
                host: document.getElementById('host').value,
                port: parseInt(document.getElementById('port').value),
                database: document.getElementById('database').value,
                username: document.getElementById('username').value,
                password: document.getElementById('password').value
            };
            
            try {
                const response = await fetch('/analyze', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(formData)
                });
                
                const data = await response.json();
                
                // 添加调试信息
                console.log('API响应数据:', data);
                console.log('表数量:', data.tables ? data.tables.length : 'undefined');
                console.log('关系数量:', data.relationships ? data.relationships.length : 'undefined');
                
                if (response.ok && data.success) {
                    currentData = data;
                    
                    // 检查数据有效性
                    if (!data.tables || data.tables.length === 0) {
                        throw new Error('没有获取到任何表数据');
                    }
                    
                    drawERDiagram(data.tables, data.relationships);
                    showTableInfo(data.tables);
                } else {
                    throw new Error(data.detail || '分析失败');
                }
            } catch (error) {
                if (loading) loading.style.display = 'none';
                if (placeholder) placeholder.style.display = 'block';
                if (errorMessage) {
                    errorMessage.textContent = '错误: ' + error.message;
                    if (errorMessage) errorMessage.style.display = 'block';
                }
            }
        });
        
        // 监听关系线样式变更
            document.getElementById('relationshipStyle').addEventListener('change', function() {
                // 如果已经有绘制的ER图，重新绘制关系线
                if (window.currentTables && window.currentRelationships) {
                    updateRelationships();
                }
            });
        
        function drawERDiagram(tables, relationships) {
            const diagram = document.getElementById('erDiagram');
            const loading = document.getElementById('loading');
            const placeholder = document.getElementById('placeholder');
            
            if (loading) loading.style.display = 'none';
            if (placeholder) placeholder.style.display = 'none';
            
            // 清除现有内容
            diagram.innerHTML = '';
            
            // 计算节点位置（优化的网格布局，避免重叠）
            const nodeWidth = 180; // 稍微减小节点宽度
            const baseHeight = 80; // 基础高度
            const rowHeight = 25; // 每行高度
            const spacing = 60; // 增加间距
            const cols = Math.min(4, Math.max(2, Math.ceil(tables.length / 3))); // 根据表数量动态调整列数
            
            // 为每个表计算合适的高度（基于列数）
            tables.forEach(table => {
                const maxColumns = 8; // 最多显示8列
                const visibleColumns = Math.min(table.columns.length, maxColumns);
                table.height = baseHeight + visibleColumns * rowHeight;
            });
            
            // 分配位置，考虑表的高度差异
            tables.forEach((table, i) => {
                const row = Math.floor(i / cols);
                const col = i % cols;
                
                // 计算当前行的总高度（取最大值）
                let rowTotalHeight = 0;
                for (let j = 0; j < cols; j++) {
                    const idx = row * cols + j;
                    if (idx < tables.length) {
                        rowTotalHeight = Math.max(rowTotalHeight, tables[idx].height);
                    }
                }
                
                // 分配位置
                table.x = col * (nodeWidth + spacing) + spacing;
                table.y = 0;
                
                // 累加前面行的高度
                for (let j = 0; j < row; j++) {
                    let prevRowHeight = 0;
                    for (let k = 0; k < cols; k++) {
                        const idx = j * cols + k;
                        if (idx < tables.length) {
                            prevRowHeight = Math.max(prevRowHeight, tables[idx].height);
                        }
                    }
                    table.y += prevRowHeight + spacing;
                }
            });
            
            // 计算SVG容器的尺寸
            const maxX = d3.max(tables, t => t.x + nodeWidth);
            const maxY = d3.max(tables, t => t.y + t.height);
            const svgWidth = Math.max(maxX + 50, 1000); // 最小宽度1000
            const svgHeight = Math.max(maxY + 50, 600); // 最小高度600
            
            // 创建SVG容器
            const svg = d3.select('#erDiagram')
                .append('svg')
                .attr('width', '100%')
                .attr('height', svgHeight)
                .attr('viewBox', `0 0 ${svgWidth} ${svgHeight}`)
                .attr('preserveAspectRatio', 'xMidYMid meet');
            
            // 移除了箭头标记定义，使用不同颜色的线条来表示关系类型
            
            // 创建一个映射来跟踪每个表对之间的关系计数，用于偏移计算
            const relationshipCount = new Map();
            relationships.forEach(rel => {
                const key1 = `${rel.from_table}-${rel.to_table}`;
                const key2 = `${rel.to_table}-${rel.from_table}`;
                if (relationshipCount.has(key1)) {
                    relationshipCount.set(key1, relationshipCount.get(key1) + 1);
                } else if (relationshipCount.has(key2)) {
                    relationshipCount.set(key2, relationshipCount.get(key2) + 1);
                } else {
                    relationshipCount.set(key1, 1);
                }
            });
            
            // 绘制表节点
            const nodes = svg.selectAll('.table-node')
                .data(tables)
                .enter()
                .append('g')
                .attr('class', 'table-node-group')
                .attr('transform', d => `translate(${d.x}, ${d.y})`)
                .call(d3.drag()
                    .on('start', dragstarted)
                    .on('drag', dragged)
                    .on('end', dragended));
            
            // 在表节点之后绘制关系线，确保关系标签显示在表节点之上
            updateRelationships();
            
            // 拖拽开始
            function dragstarted(event, d) {
                d3.select(this).raise().classed('active', true);
            }
            
            // 拖拽过程中
            function dragged(event, d) {
                // 更新节点位置
                d3.select(this).attr('transform', `translate(${event.x}, ${event.y})`);
                
                // 更新表数据中的位置
                d.x = event.x;
                d.y = event.y;
                
                // 重新绘制关系线
                updateRelationships();
            }
            
            // 拖拽结束
            function dragended(event, d) {
                d3.select(this).classed('active', false);
                
                // 最后更新一次关系线
                updateRelationships();
            }
            
            // 计算两个表之间最优的连接点
            function calculateOptimalConnection(fromTable, toTable, nodeWidth, relationship) {
                // 获取两个表的中心坐标
                const fromCenterX = fromTable.x + nodeWidth / 2;
                const fromCenterY = fromTable.y + fromTable.height / 2;
                const toCenterX = toTable.x + nodeWidth / 2;
                const toCenterY = toTable.y + toTable.height / 2;
                
                // 计算两个表中心之间的角度
                const angle = Math.atan2(toCenterY - fromCenterY, toCenterX - fromCenterX);
                
                // 检查是否是自关联关系
                const isSelfRelationship = fromTable.name === toTable.name;
                
                // 根据角度选择fromTable的最佳边缘点
                let x1, y1;
                if (isSelfRelationship) {
                    // 自关联关系：强制起点在表的右侧
                    x1 = fromTable.x + nodeWidth;
                    y1 = fromCenterY - 40; // 稍微偏上，为圆弧留出空间
                } else if (Math.abs(Math.cos(angle)) > Math.abs(Math.sin(angle))) {
                    // 水平方向更近
                    if (Math.cos(angle) > 0) {
                        // 右侧
                        x1 = fromTable.x + nodeWidth;
                    } else {
                        // 左侧
                        x1 = fromTable.x;
                    }
                    y1 = fromCenterY;
                } else {
                    // 垂直方向更近
                    x1 = fromCenterX;
                    if (Math.sin(angle) > 0) {
                        // 底部
                        y1 = fromTable.y + fromTable.height;
                    } else {
                        // 顶部
                        y1 = fromTable.y;
                    }
                }
                
                // 根据相对位置调整toTable的最佳边缘点
                let x2, y2;
                // 计算两个表相对于彼此的位置
                const dx = toCenterX - fromCenterX;
                const dy = toCenterY - fromCenterY;
                
                if (isSelfRelationship) {
                    // 自关联关系：强制终点也在表的右侧，与起点错开位置
                    x2 = toTable.x + nodeWidth;
                    y2 = toCenterY + 40; // 稍微偏下，与起点形成对比，为圆弧留出空间
                } else if (dx > nodeWidth) {
                    // 如果源表在目标表的左侧，连接到目标表的左侧
                    x2 = toTable.x;
                } 
                // 如果源表在目标表的右侧，连接到目标表的右侧
                else if (dx < -nodeWidth) {
                    x2 = toTable.x + nodeWidth;
                } 
                // 如果源表在目标表的上方，连接到目标表的顶部
                else if (dy > nodeWidth) {
                    x2 = toCenterX;
                    y2 = toTable.y;
                } 
                // 如果源表在目标表的下方，连接到目标表的底部
                else if (dy < -nodeWidth) {
                    x2 = toCenterX;
                    y2 = toTable.y + toTable.height;
                } 
                // 如果两表重叠或非常接近，选择默认的左侧连接
                else {
                    x2 = toTable.x;
                }
                
                // 如果x2已经设置但y2未设置，计算y2
                if (x2 && y2 === undefined) {
                    y2 = toCenterY;
                }
                
                // 根据关联列调整Y坐标，但确保连接点始终位于表的外部边缘
                if (relationship) {
                    const fromColumnIndex = fromTable.columns.findIndex(col => col.name === relationship.from_column);
                    const toColumnIndex = toTable.columns.findIndex(col => col.name === relationship.to_column);
                    
                    // 列的起始Y位置：55 + i * 22
                    if (fromColumnIndex >= 0) {
                        const columnY = fromTable.y + 55 + fromColumnIndex * 22; // 列的中间位置
                        
                        // 确保连接点在表的外部边缘
                        if (x1 === fromTable.x) {
                            // 连接到左侧，保持x坐标在左边缘
                            y1 = columnY;
                        } else if (x1 === fromTable.x + nodeWidth) {
                            // 连接到右侧，保持x坐标在右边缘
                            y1 = columnY;
                        } else {
                            // 连接到顶部或底部，需要调整x坐标到边缘
                            if (Math.cos(angle) > 0) {
                                x1 = fromTable.x + nodeWidth; // 右侧
                            } else {
                                x1 = fromTable.x; // 左侧
                            }
                            y1 = columnY;
                        }
                    }
                    if (toColumnIndex >= 0) {
                        const columnY = toTable.y + 55 + toColumnIndex * 22; // 列的中间位置
                        
                        // 确保连接点在表的外部边缘
                        if (x2 === toTable.x) {
                            // 连接到左侧，保持x坐标在左边缘
                            y2 = columnY;
                        } else if (x2 === toTable.x + nodeWidth) {
                            // 连接到右侧，保持x坐标在右边缘
                            y2 = columnY;
                        } else {
                            // 连接到顶部或底部，需要调整x坐标到边缘
                            if (dx > 0) {
                                x2 = toTable.x; // 从右侧来的连接到左侧
                            } else {
                                x2 = toTable.x + nodeWidth; // 从左侧来的连接到右侧
                            }
                            y2 = columnY;
                        }
                    }
                }
                
                return { x1, y1, x2, y2 };
            }
            
            // 更新所有关系线
            function updateRelationships() {
                // 清除现有的关系线
                svg.selectAll('.relationship-group').remove();
                
                // 重新绘制关系线
                relationships.forEach((rel, index) => {
                    const fromTable = tables.find(t => t.name === rel.from_table);
                    const toTable = tables.find(t => t.name === rel.to_table);
                    
                    if (fromTable && toTable) {
                        // 计算最优的连接点
                        const { x1, y1, x2, y2 } = calculateOptimalConnection(fromTable, toTable, nodeWidth, rel);
                        
                        // 创建关系线组
                        const relationshipGroup = svg.append('g')
                            .attr('class', 'relationship-group');
                        
                        // 获取关系类型和设置颜色
                        const cardinality = rel.cardinality || getRelationshipType(rel);
                        
                        // 解析基数关系
                        let fromCardinality = '1';
                        let toCardinality = 'N';
                        let lineColor = '#007bff'; // 默认颜色
                        
                        // 设置线条颜色和基数方向
                        if (cardinality === '1:1') {
                            fromCardinality = '1';
                            toCardinality = '1';
                            lineColor = '#28a745'; // 绿色表示1:1关系
                        } else if (cardinality === 'N:M') {
                            fromCardinality = 'N';
                            toCardinality = 'M';
                            lineColor = '#dc3545'; // 红色表示N:M关系
                        } else {
                            // 对于1:N关系，修正基数方向
                            // 常见情况是：从表(外键表)指向主表，此时应该交换基数标记
                            // 因为在这种情况下，从表是多的一方(N)，主表是一的一方(1)
                            fromCardinality = 'N';
                            toCardinality = '1';
                        }
                        
                        // 计算曼哈顿路径的中间点，并添加偏移避免重叠
                        const key1 = `${rel.from_table}-${rel.to_table}`;
                        const key2 = `${rel.to_table}-${rel.from_table}`;
                        const count = relationshipCount.get(key1) || relationshipCount.get(key2) || 1;
                        
                        // 基础中间点
                        let midX = (x1 + x2) / 2;
                        
                        // 根据关系的索引计算垂直偏移，避免重叠
                        const verticalOffset = (index % 3 - 1) * 30; // -30, 0, +30 三种偏移
                        
                        // 获取用户选择的关系线样式
                            const relationshipStyle = document.getElementById('relationshipStyle').value;
                            
                            // 特殊处理: 如果两个表在垂直方向距离较远，则使用S型路径
                            const midY = (y1 + y2) / 2;
                            
                            // 检查是否是自关联关系
                            const isSelfRelationship = fromTable.name === toTable.name;
                            
                            if (relationshipStyle === 'curve') {
                                // 绘制贝塞尔曲线关系线
                                relationshipGroup.append('path')
                                    .attr('class', 'relationship-line')
                                    .attr('d', () => {
                                        if (isSelfRelationship) {
                                            // 自关联关系：绘制90度圆弧，直径等于起点到终点的距离
                                            const deltaX = x2 - x1;
                                            const deltaY = y2 - y1;
                                            const diameter = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
                                            const radius = diameter / 2;
                                            
                                            // 计算圆弧中心点（中点）
                                            const centerX = (x1 + x2) / 2;
                                            const centerY = (y1 + y2) / 2;
                                            
                                            // 使用SVG弧形命令绘制90度圆弧
                                            // A命令参数：rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y
                                            // 这里使用90度圆弧，从起点到终点
                                            return `M ${x1} ${y1} A ${radius} ${radius} 0 0 1 ${x2} ${y2}`;
                                        } else {
                                            // 非自关联关系：使用普通贝塞尔曲线
                                            // 计算控制点，创建平滑曲线
                                            const controlPointOffset = 150;
                                            const cp1x = x1 + (x2 - x1) / 3;
                                            const cp1y = y1;
                                            const cp2x = x1 + (x2 - x1) * 2 / 3;
                                            const cp2y = y2;
                                            
                                            return `M ${x1} ${y1} C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${x2} ${y2}`;
                                        }
                                    })
                                    .style('stroke-width', '2px')
                                    .style('stroke-dasharray', '0')
                                    .style('stroke', lineColor)
                                    .style('stroke-linecap', 'round')
                                    .style('fill', 'none')
                                    .style('filter', 'drop-shadow(1px 1px 1px rgba(0,0,0,0.2))');
                            } else {
                                // 原始的直线/折线关系线
                                // 如果两个表在同一水平线上或非常接近，使用标准的垂直+水平路径
                                if (Math.abs(y1 - y2) < 100) {
                                    // 绘制水平线段（从起点到中间点）
                                    relationshipGroup.append('line')
                                        .attr('class', 'relationship-line')
                                        .attr('x1', x1)
                                        .attr('y1', y1)
                                        .attr('x2', midX)
                                        .attr('y2', y1)
                                        .style('stroke-width', '2px')
                                        .style('stroke-dasharray', '0')
                                        .style('stroke', lineColor)
                                        .style('stroke-linecap', 'round')
                                        .style('filter', 'drop-shadow(1px 1px 1px rgba(0,0,0,0.2))');
                                    
                                    // 绘制垂直线段（从中间点到终点的垂直位置）
                                    relationshipGroup.append('line')
                                        .attr('class', 'relationship-line')
                                        .attr('x1', midX)
                                        .attr('y1', y1)
                                        .attr('x2', midX)
                                        .attr('y2', y2)
                                        .style('stroke-width', '2px')
                                        .style('stroke-dasharray', '0')
                                        .style('stroke', lineColor)
                                        .style('stroke-linecap', 'round')
                                        .style('filter', 'drop-shadow(1px 1px 1px rgba(0,0,0,0.2))');
                                    
                                    // 绘制水平线段（从中间点的垂直位置到终点）
                                    relationshipGroup.append('line')
                                        .attr('class', 'relationship-line')
                                        .attr('x1', midX)
                                        .attr('y1', y2)
                                        .attr('x2', x2)
                                        .attr('y2', y2)
                                        .style('stroke-width', '2px')
                                        .style('stroke-dasharray', '0')
                                        .style('stroke', lineColor)
                                        .style('stroke-linecap', 'round')
                                        .style('filter', 'drop-shadow(1px 1px 1px rgba(0,0,0,0.2))');
                                } else {
                                    // 对于垂直距离较远的表，使用S型路径，减少交叉
                                    // 第一个水平段
                                    const midPoint1 = x1 + (midX - x1) / 2;
                                    relationshipGroup.append('line')
                                        .attr('class', 'relationship-line')
                                        .attr('x1', x1)
                                        .attr('y1', y1)
                                        .attr('x2', midPoint1)
                                        .attr('y2', y1)
                                        .style('stroke-width', '2px')
                                        .style('stroke-dasharray', '0')
                                        .style('stroke', lineColor)
                                        .style('stroke-linecap', 'round')
                                        .style('filter', 'drop-shadow(1px 1px 1px rgba(0,0,0,0.2))');
                                    
                                    // 第一个垂直段（带偏移）
                                    relationshipGroup.append('line')
                                        .attr('class', 'relationship-line')
                                        .attr('x1', midPoint1)
                                        .attr('y1', y1)
                                        .attr('x2', midPoint1)
                                        .attr('y2', midY + verticalOffset)
                                        .style('stroke-width', '2px')
                                        .style('stroke-dasharray', '0')
                                        .style('stroke', lineColor)
                                        .style('stroke-linecap', 'round')
                                        .style('filter', 'drop-shadow(1px 1px 1px rgba(0,0,0,0.2))');
                                    
                                    // 中间水平段（带偏移）
                                    const midPoint2 = x2 - (x2 - midX) / 2;
                                    relationshipGroup.append('line')
                                        .attr('class', 'relationship-line')
                                        .attr('x1', midPoint1)
                                        .attr('y1', midY + verticalOffset)
                                        .attr('x2', midPoint2)
                                        .attr('y2', midY + verticalOffset)
                                        .style('stroke-width', '2px')
                                        .style('stroke-dasharray', '0')
                                        .style('stroke', lineColor)
                                        .style('stroke-linecap', 'round')
                                        .style('filter', 'drop-shadow(1px 1px 1px rgba(0,0,0,0.2))');
                                    
                                    // 第二个垂直段
                                    relationshipGroup.append('line')
                                        .attr('class', 'relationship-line')
                                        .attr('x1', midPoint2)
                                        .attr('y1', midY + verticalOffset)
                                        .attr('x2', midPoint2)
                                        .attr('y2', y2)
                                        .style('stroke-width', '2px')
                                        .style('stroke-dasharray', '0')
                                        .style('stroke', lineColor)
                                        .style('stroke-linecap', 'round')
                                        .style('filter', 'drop-shadow(1px 1px 1px rgba(0,0,0,0.2))');
                                    
                                    // 第二个水平段
                                    relationshipGroup.append('line')
                                        .attr('class', 'relationship-line')
                                        .attr('x1', midPoint2)
                                        .attr('y1', y2)
                                        .attr('x2', x2)
                                        .attr('y2', y2)
                                        .style('stroke-width', '2px')
                                        .style('stroke-dasharray', '0')
                                        .style('stroke', lineColor)
                                        .style('stroke-linecap', 'round')
                                        .style('filter', 'drop-shadow(1px 1px 1px rgba(0,0,0,0.2))');
                                }
                            }
                        
                        // 计算基数标志位置，确保不放置在表矩形内部
                        let fromLabelX, fromLabelY, toLabelX, toLabelY;
                        
                        // 计算起点基数标志位置
                        if (x1 === fromTable.x) {
                            // 连接在左侧，将标志放在更左的位置
                            fromLabelX = x1 - 30;
                            fromLabelY = y1;
                        } else if (x1 === fromTable.x + nodeWidth) {
                            // 连接在右侧，将标志放在更右的位置
                            fromLabelX = x1 + 30;
                            fromLabelY = y1;
                        } else {
                            // 连接在顶部或底部，根据角度决定左右位置
                            if (Math.cos(angle) > 0) {
                                fromLabelX = x1 + 30;
                                fromLabelY = y1;
                            } else {
                                fromLabelX = x1 - 30;
                                fromLabelY = y1;
                            }
                        }
                        
                        // 计算终点基数标志位置
                        if (x2 === toTable.x) {
                            // 连接在左侧，将标志放在更左的位置
                            toLabelX = x2 - 30;
                            toLabelY = y2;
                        } else if (x2 === toTable.x + nodeWidth) {
                            // 连接在右侧，将标志放在更右的位置
                            toLabelX = x2 + 30;
                            toLabelY = y2;
                        } else {
                            // 连接在顶部或底部，根据相对位置决定左右位置
                            if (dx > 0) {
                                toLabelX = x2 - 30;
                                toLabelY = y2;
                            } else {
                                toLabelX = x2 + 30;
                                toLabelY = y2;
                            }
                        }
                        
                        // 在起点显示基数
                        // 先添加背景矩形
                        relationshipGroup.append('rect')
                            .attr('x', fromLabelX - 14)
                            .attr('y', fromLabelY - 14)
                            .attr('width', 28)
                            .attr('height', 28)
                            .attr('rx', 6)
                            .attr('ry', 6)
                            .style('fill', '#ffffff')
                            .style('stroke', '#333')
                            .style('stroke-width', '2px')
                            .style('filter', 'drop-shadow(2px 2px 4px rgba(0,0,0,0.3))');
                        
                        // 再添加起点文字
                        relationshipGroup.append('text')
                            .attr('x', fromLabelX)
                            .attr('y', fromLabelY)
                            .attr('text-anchor', 'middle')
                            .attr('class', 'table-text')
                            .style('font-size', '18px')
                            .style('font-weight', 'bold')
                            .style('fill', lineColor)
                            .style('text-shadow', '1px 1px 2px rgba(255,255,255,0.8), -1px -1px 2px rgba(255,255,255,0.8)')
                            .text(fromCardinality);
                        
                        // 在终点显示基数
                        // 先添加背景矩形
                        relationshipGroup.append('rect')
                            .attr('x', toLabelX - 14)
                            .attr('y', toLabelY - 14)
                            .attr('width', 28)
                            .attr('height', 28)
                            .attr('rx', 6)
                            .attr('ry', 6)
                            .style('fill', '#ffffff')
                            .style('stroke', '#333')
                            .style('stroke-width', '2px')
                            .style('filter', 'drop-shadow(2px 2px 4px rgba(0,0,0,0.3))');
                        
                        // 再添加终点文字
                        relationshipGroup.append('text')
                            .attr('x', toLabelX)
                            .attr('y', toLabelY)
                            .attr('text-anchor', 'middle')
                            .attr('class', 'table-text')
                            .style('font-size', '18px')
                            .style('font-weight', 'bold')
                            .style('fill', lineColor)
                            .style('text-shadow', '1px 1px 2px rgba(255,255,255,0.8), -1px -1px 2px rgba(255,255,255,0.8)')
                            .text(toCardinality);
                    }
                });
            }
            
            // 表体背景
            nodes.append('rect')
                .attr('class', 'table-node')
                .attr('width', nodeWidth)
                .attr('height', d => d.height)
                .attr('rx', 8)
                .attr('ry', 8)
                .style('fill', '#f8f9fa')
                .style('stroke', '#007bff')
                .style('stroke-width', '2px')
                .style('filter', 'drop-shadow(2px 2px 4px rgba(0,0,0,0.1))');
            
            // 表头背景
            nodes.append('rect')
                .attr('class', 'table-header')
                .attr('width', nodeWidth)
                .attr('height', 35)
                .attr('rx', 8)
                .attr('ry', 8)
                .style('fill', '#007bff')
                .style('stroke', '#0056b3')
                .style('stroke-width', '2px');
            
            // 表名和图标
            const headerGroup = nodes.append('g')
                .attr('transform', `translate(15, 23)`); // 靠左对齐，从15px开始
            
            // 表名前的钥匙图标
            headerGroup.append('text')
                .attr('x', 0)
                .attr('y', 0)
                .attr('text-anchor', 'start')
                .attr('class', 'header-text')
                .style('fill', 'white')
                .style('font-size', '16px')
                .text('🔑');
            
            // 表名
            headerGroup.append('text')
                .attr('x', 25)
                .attr('y', 0)
                .attr('text-anchor', 'start')
                .attr('class', 'table-text header-text')
                .style('fill', 'white')
                .style('font-weight', 'bold')
                .style('font-size', '14px')
                .text(d => d.name);
            
            // 列信息
            nodes.append('g')
                .attr('class', 'columns')
                .selectAll('.column')
                .data(d => d.columns.slice(0, 8)) // 最多显示8列
                .enter()
                .append('g')
                .attr('transform', (d, i) => `translate(10, ${55 + i * 22})`)
                .each(function(d, i) {
                    // 列图标
                    const iconX = 0;
                    const iconY = 3;
                    
                    d3.select(this).append('text')
                        .attr('x', iconX)
                        .attr('y', iconY)
                        .attr('text-anchor', 'start')
                        .style('font-size', '12px')
                        .text(d.is_primary_key ? '🔑' : d.is_foreign_key ? '🔗' : '📄');
                    
                    // 列名和类型
                    d3.select(this).append('text')
                        .attr('x', 20)
                        .attr('y', iconY)
                        .attr('text-anchor', 'start')
                        .attr('class', d => {
                            let className = 'table-text column-text';
                            if (d.is_primary_key) className += ' primary-key';
                            if (d.is_foreign_key) className += ' foreign-key';
                            return className;
                        })
                        .style('font-size', '12px')
                        .style('font-weight', d => d.is_primary_key ? 'bold' : 'normal')
                        .style('font-style', d => d.is_foreign_key ? 'italic' : 'normal')
                        .text(d => `${d.name} (${d.data_type})`);
                });
            
            // 如果列太多，显示省略号
            nodes.filter(d => d.columns.length > 8)
                .append('text')
                .attr('class', 'table-text column-text')
                .attr('x', 10)
                .attr('y', d => 55 + 8 * 22)
                .style('font-size', '12px')
                .text('...');
        }
        
        function showTableInfo(tables) {
            const tableInfo = document.getElementById('tableInfo');
            const tableList = document.getElementById('tableList');
            
            if (!tableList) {
                console.error('tableList element not found');
                return;
            }
            
            tableList.innerHTML = '';
            
            tables.forEach(table => {
                const tableDiv = document.createElement('div');
                tableDiv.className = 'mb-2 table-item';
                tableDiv.innerHTML = `
                    <div class="d-flex align-items-center">
                        <div class="form-check me-2">
                            <input class="form-check-input table-checkbox" type="checkbox" 
                                   id="table_${table.name}" value="${table.name}" checked>
                        </div>
                        <div class="flex-grow-1">
                            <label class="form-check-label mb-0" for="table_${table.name}">
                                <strong>${table.name}</strong>
                                <small class="text-muted d-block">${table.columns.length} 列</small>
                            </label>
                        </div>
                    </div>
                `;
                tableList.appendChild(tableDiv);
            });
            
            if (tableInfo) tableInfo.style.display = 'block';
            
            // 更新表数量统计
            function updateTableCount() {
                const totalTables = document.querySelectorAll('.table-item').length;
                const visibleTables = document.querySelectorAll('.table-item:not(.hidden)').length;
                const selectedTables = document.querySelectorAll('.table-checkbox:checked').length;
                
                const tableInfoTitle = document.querySelector('#tableInfo h6');
                if (tableInfoTitle) {
                    tableInfoTitle.innerHTML = `<i class="fas fa-info-circle"></i> 表信息 (${selectedTables}/${visibleTables})`;
                }
            }
            
            // 绑定搜索功能
            document.getElementById('tableSearch').addEventListener('input', function() {
                const searchTerm = this.value.toLowerCase();
                const tableItems = document.querySelectorAll('.table-item');
                
                tableItems.forEach(item => {
                    const tableName = item.querySelector('strong').textContent.toLowerCase();
                    if (tableName.includes(searchTerm)) {
                        item.classList.remove('hidden');
                    } else {
                        item.classList.add('hidden');
                    }
                });
                
                updateTableCount();
            });
            
            // 绑定复选框变化事件
            document.querySelectorAll('.table-checkbox').forEach(checkbox => {
                checkbox.addEventListener('change', updateTableCount);
            });
            
            // 初始化数量统计
            updateTableCount();
            
            // 绑定全选/全不选按钮事件
            document.getElementById('selectAllBtn').addEventListener('click', function() {
                const checkboxes = document.querySelectorAll('.table-checkbox');
                checkboxes.forEach(checkbox => checkbox.checked = true);
                updateTableCount();
            });
            
            document.getElementById('deselectAllBtn').addEventListener('click', function() {
                const checkboxes = document.querySelectorAll('.table-checkbox');
                checkboxes.forEach(checkbox => checkbox.checked = false);
                updateTableCount();
            });
            
            // 绑定刷新ER图按钮事件
            document.getElementById('refreshDiagramBtn').addEventListener('click', function() {
                refreshERDiagram();
            });
        }
        
        function showSuccessMessage(message) {
            // 创建成功提示元素
            const successDiv = document.createElement('div');
            successDiv.className = 'alert alert-success alert-dismissible fade show position-fixed';
            successDiv.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 250px;';
            successDiv.innerHTML = `
                <i class="fas fa-check-circle"></i> ${message}
                <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
            `;
            
            document.body.appendChild(successDiv);
            
            // 3秒后自动消失
            setTimeout(() => {
                if (successDiv.parentNode) {
                    successDiv.remove();
                }
            }, 3000);
        }
        
        function refreshERDiagram() {
            if (!currentData) return;
            
            // 获取选中的表
            const selectedTables = [];
            const checkboxes = document.querySelectorAll('.table-checkbox:checked');
            checkboxes.forEach(checkbox => {
                selectedTables.push(checkbox.value);
            });
            
            if (selectedTables.length === 0) {
                alert('请至少选择一个表！');
                return;
            }
            
            // 显示加载状态
            const loading = document.getElementById('loading');
            const placeholder = document.getElementById('placeholder');
            const errorMessage = document.getElementById('errorMessage');
            
            if (loading) loading.style.display = 'block';
            if (placeholder) placeholder.style.display = 'none';
            if (errorMessage) errorMessage.style.display = 'none';
            
            // 获取当前的数据库连接信息
            const formData = {
                db_type: document.getElementById('dbType').value,
                host: document.getElementById('host').value,
                port: parseInt(document.getElementById('port').value),
                database: document.getElementById('database').value,
                username: document.getElementById('username').value,
                password: document.getElementById('password').value
            };
            
            // 发送筛选请求到后端
            fetch('/analyze', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    ...formData,
                    tables: selectedTables
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.success) {
                    // 重新绘制ER图
                    drawERDiagram(data.tables, data.relationships);
                    
                    // 显示成功提示
                    showSuccessMessage('ER图已根据选中的表刷新');
                } else {
                    throw new Error(data.detail || '筛选失败');
                }
            })
            .catch(error => {
                if (loading) loading.style.display = 'none';
                if (placeholder) placeholder.style.display = 'block';
                if (errorMessage) {
                    errorMessage.textContent = '错误: ' + error.message;
                    if (errorMessage) errorMessage.style.display = 'block';
                }
            });
        }
    </script>
</body>
</html>